/**
  ******************************************************************************
  * @file    stm32f4xx_hash_sha1.c
  * @author  MCD Application Team
  * @version V1.4.0
  * @date    04-August-2014
  * @brief   This file provides high level functions to compute the HASH SHA1 and
  *          HMAC SHA1 Digest of an input message.
  *          It uses the stm32f4xx_hash.c/.h drivers to access the STM32F4xx HASH
  *          peripheral.
  *
@verbatim
 ===================================================================
                 ##### How to use this driver #####
 ===================================================================
 [..]
   (#) Enable The HASH controller clock using
       RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_HASH, ENABLE); function.

   (#) Calculate the HASH SHA1 Digest using HASH_SHA1() function.

   (#) Calculate the HMAC SHA1 Digest using HMAC_SHA1() function.

@endverbatim
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hash.h"

/** @addtogroup STM32F4xx_StdPeriph_Driver
  * @{
  */

/** @defgroup HASH
  * @brief HASH driver modules
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define SHA1BUSY_TIMEOUT    ((uint32_t) 0x00010000)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup HASH_Private_Functions
  * @{
  */

/** @defgroup HASH_Group6 High Level SHA1 functions
 *  @brief   High Level SHA1 Hash and HMAC functions
 *
@verbatim
 ===============================================================================
               ##### High Level SHA1 Hash and HMAC functions #####
 ===============================================================================


@endverbatim
  * @{
  */

/**
  * @brief  Compute the HASH SHA1 digest.
  * @param  Input: pointer to the Input buffer to be treated.
  * @param  Ilen: length of the Input buffer.
  * @param  Output: the returned digest
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: digest computation done
  *          - ERROR: digest computation failed
  */
ErrorStatus HASH_SHA1(uint8_t *Input, uint32_t Ilen, uint8_t Output[20])
{
	HASH_InitTypeDef SHA1_HASH_InitStructure;
	HASH_MsgDigest SHA1_MessageDigest;
	__IO uint16_t nbvalidbitsdata = 0;
	uint32_t i = 0;
	__IO uint32_t counter = 0;
	uint32_t busystatus = 0;
	ErrorStatus status = SUCCESS;
	uint32_t inputaddr  = (uint32_t)Input;
	uint32_t outputaddr = (uint32_t)Output;

	/* Number of valid bits in last word of the Input data */
	nbvalidbitsdata = 8 * (Ilen % 4);

	/* HASH peripheral initialization */
	HASH_DeInit();

	/* HASH Configuration */
	SHA1_HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_SHA1;
	SHA1_HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HASH;
	SHA1_HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
	HASH_Init(&SHA1_HASH_InitStructure);

	/* Configure the number of valid bits in last word of the data */
	HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);

	/* Write the Input block in the IN FIFO */
	for(i = 0; i < Ilen; i += 4)
	{
		HASH_DataIn(*(uint32_t *)inputaddr);
		inputaddr += 4;
	}

	/* Start the HASH processor */
	HASH_StartDigest();

	/* wait until the Busy flag is RESET */
	do
	{
		busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
		counter++;
	}
	while ((counter != SHA1BUSY_TIMEOUT) && (busystatus != RESET));

	if (busystatus != RESET)
	{
		status = ERROR;
	}
	else
	{
		/* Read the message digest */
		HASH_GetDigest(&SHA1_MessageDigest);
		*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[0]);
		outputaddr += 4;
		*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[1]);
		outputaddr += 4;
		*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[2]);
		outputaddr += 4;
		*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[3]);
		outputaddr += 4;
		*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[4]);
	}
	return status;
}

/**
  * @brief  Compute the HMAC SHA1 digest.
  * @param  Key: pointer to the Key used for HMAC.
  * @param  Keylen: length of the Key used for HMAC.
  * @param  Input: pointer to the Input buffer to be treated.
  * @param  Ilen: length of the Input buffer.
  * @param  Output: the returned digest
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: digest computation done
  *          - ERROR: digest computation failed
  */
ErrorStatus HMAC_SHA1(uint8_t *Key, uint32_t Keylen, uint8_t *Input,
		      uint32_t Ilen, uint8_t Output[20])
{
	HASH_InitTypeDef SHA1_HASH_InitStructure;
	HASH_MsgDigest SHA1_MessageDigest;
	__IO uint16_t nbvalidbitsdata = 0;
	__IO uint16_t nbvalidbitskey = 0;
	uint32_t i = 0;
	__IO uint32_t counter = 0;
	uint32_t busystatus = 0;
	ErrorStatus status = SUCCESS;
	uint32_t keyaddr    = (uint32_t)Key;
	uint32_t inputaddr  = (uint32_t)Input;
	uint32_t outputaddr = (uint32_t)Output;

	/* Number of valid bits in last word of the Input data */
	nbvalidbitsdata = 8 * (Ilen % 4);

	/* Number of valid bits in last word of the Key */
	nbvalidbitskey = 8 * (Keylen % 4);

	/* HASH peripheral initialization */
	HASH_DeInit();

	/* HASH Configuration */
	SHA1_HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_SHA1;
	SHA1_HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HMAC;
	SHA1_HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
	if(Keylen > 64)
	{
		/* HMAC long Key */
		SHA1_HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_LongKey;
	}
	else
	{
		/* HMAC short Key */
		SHA1_HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_ShortKey;
	}
	HASH_Init(&SHA1_HASH_InitStructure);

	/* Configure the number of valid bits in last word of the Key */
	HASH_SetLastWordValidBitsNbr(nbvalidbitskey);

	/* Write the Key */
	for(i = 0; i < Keylen; i += 4)
	{
		HASH_DataIn(*(uint32_t *)keyaddr);
		keyaddr += 4;
	}

	/* Start the HASH processor */
	HASH_StartDigest();

	/* wait until the Busy flag is RESET */
	do
	{
		busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
		counter++;
	}
	while ((counter != SHA1BUSY_TIMEOUT) && (busystatus != RESET));

	if (busystatus != RESET)
	{
		status = ERROR;
	}
	else
	{
		/* Configure the number of valid bits in last word of the Input data */
		HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);

		/* Write the Input block in the IN FIFO */
		for(i = 0; i < Ilen; i += 4)
		{
			HASH_DataIn(*(uint32_t *)inputaddr);
			inputaddr += 4;
		}

		/* Start the HASH processor */
		HASH_StartDigest();


		/* wait until the Busy flag is RESET */
		counter = 0;
		do
		{
			busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
			counter++;
		}
		while ((counter != SHA1BUSY_TIMEOUT) && (busystatus != RESET));

		if (busystatus != RESET)
		{
			status = ERROR;
		}
		else
		{
			/* Configure the number of valid bits in last word of the Key */
			HASH_SetLastWordValidBitsNbr(nbvalidbitskey);

			/* Write the Key */
			keyaddr = (uint32_t)Key;
			for(i = 0; i < Keylen; i += 4)
			{
				HASH_DataIn(*(uint32_t *)keyaddr);
				keyaddr += 4;
			}

			/* Start the HASH processor */
			HASH_StartDigest();

			/* wait until the Busy flag is RESET */
			counter = 0;
			do
			{
				busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
				counter++;
			}
			while ((counter != SHA1BUSY_TIMEOUT) && (busystatus != RESET));

			if (busystatus != RESET)
			{
				status = ERROR;
			}
			else
			{
				/* Read the message digest */
				HASH_GetDigest(&SHA1_MessageDigest);
				*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[0]);
				outputaddr += 4;
				*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[1]);
				outputaddr += 4;
				*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[2]);
				outputaddr += 4;
				*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[3]);
				outputaddr += 4;
				*(uint32_t *)(outputaddr)  = __REV(SHA1_MessageDigest.Data[4]);
			}
		}
	}
	return status;
}
/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
